#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include "nm.h"

#define SINE_SHIBBOLETH 1

using namespace std;

class Interface
{
    public:
    int interfaceEval(char* interface);
    int interfaceStatus(char* interface);
};

int Interface::interfaceEval(char*interface)
{
    char inter[20] = {0};
    int j=0;
    for(int i=0;i<=strlen(interface);i++)
    {
        if(interface[i]!=' ' && interface[i]!='\0')
        {
            inter[j]=interface[i];
            j++;
        }
        else
        {
            //j++;
            inter[j]='\0';
            int ret=interfaceStatus(inter);
            if(!ret)
                return 0;       // make it zero
            //if(!strcmp(inter,"wlan0"))
		if(SINE_SHIBBOLETH && !sine_shibboleth(inter))
			return 0;	

	    //memset(inter,0,7);
            j=0;
        }
    }
    return 1;
}

int Interface::interfaceStatus(char* interface)
{
    cout<<"Checking interface "<<interface<<endl;	
    char buffer[10] = {0};
   	sine_getIfStatus(interface, buffer);
	if(!strcmp(buffer, "up"))
		return 1;
    	else
    	return 0;
  
    
        //cout<<"Comparing - "<<interface<<endl;
   /* 	if(!strcmp(interface,"wlan0"))
		return 1;
		else
		return 0;
   */
}

class Location
{
    public:
    int resolveLocation(char* loc);
    int locationStatus(char* loc);
};

int Location::resolveLocation(char* location)
{
    char loc[15] = {0};
    int j=0;
    //cout<<"Processing - "<<location<<endl;
    for(int i=0;i<=strlen(location);i++)
    {
        if(location[i]!=' ' && location[i]!='\0')
        {
            loc[j]=location[i];
            j++;
        }
        else
        {
            //j++;
            loc[j]='\0';
            int ret=locationStatus(loc);
            if(ret)
                return 1;       // make it zero
            //memset(loc,0,15);
            j=0;
        }
    }
    //cout<<"Should reach here\m";
    return 0;
}

int Location::locationStatus(char* location)
{
    char buffer[10] = {0};
/*	sine_getLocation(buffer);
	if(!strcmp(buffer, location))
		return 1;
    	else
    	return 0;
*/    
        //cout<<"Comparing - "<<location<<endl;
    	if(!strcmp(location,"columbia"))
		return 1;
		else
		return 0;
    	
}



class Bandwidth
{
    public:
    int resolveBandwidth(char* inter, int band);
};

int Bandwidth::resolveBandwidth(char* inter, int band)
{
    int obtBand=510;
    cout<<"Got - "<<inter<<endl;	
    obtBand = sine_getBandwidth(inter);
    //obtBand=atoi(strBand);
    if(band<=obtBand)
        return 1;
    else
        return 0;
}

class Cost
{
    public:
    int resolveCost(char* inter, int cost, int offset);
};

int Cost::resolveCost(char* inter, int cost, int offset)
{
    int obtCost=1;
    obtCost = sine_getCost(inter);
    //obtCost=atoi(strCost);
    if(cost+offset>=obtCost)
        return 1;
    else
        return 0;
}

class DownloadLimit
{
    int resolvedwnLimit(int dwnlimit);
};

class ConditionList
{
    public:
    Location* location;
    Bandwidth* bandwidth;
    Cost* cost;
    DownloadLimit* dwnLimit;
};

class Action
{
    public:
    char* interface;
};

class Rules     // Similar to Conditions
{
    public:
    ConditionList* condList;
    Action* action;
};

class Policy
{
    public:
    int policyID;
    int appID;
    Rules* rule;
};

char* policyModel(int, int);
int evaluate (Action*, ConditionList*, char*, char*);
int parseCondition(char* tempStore,char* metadata,char* data, char* str,int condOffest,int init2,int dataIndex, int j);
/*
int main()
{
    char* interfaces=policyModel(77,1000);
    if(interfaces==NULL)
        cout<<"No available interfaces";
    else
        cout<<interfaces;
    return 0;
}*/

char* policyModel(int appID, int sockfd)
{
    //cout<<"trying to open file";
    ifstream in("configPolicy.txt"); // input
    if(!in) {
        cout << "Cannot open input file.\n";
        return NULL;
    }

    char strAppID[10] = {0};
    char str[150] = {0};
    char metadata[20] = {0};

    while(in)
    {
        char strAppID[10] = {0};
	//cout<<"Very first\n";
        in.getline(str, 150);
        //cout<<"Call reaches here\n";
        int dataIndex=0;
        unsigned int i=0;
       	for(i=0;i<strlen(str);i++)
   	{
            if(str[i]!=','){
           		strAppID[dataIndex]=str[i];
       			dataIndex++;
            }
	        else{
	             strAppID[dataIndex]='\0';
	             break;
	        }
    	}
    	int appIDSearch=atoi(strAppID);
    	if(appIDSearch!=appID)
    	{
    	    //delete str;
    	    //delete strAppID;
            //free(str);
            //cout<<"no - "<<appIDSearch<<endl;
    	    continue;
    	}

        else
        {
            //delete strAppID;
            cout<<"Working for appID "<<appIDSearch<<endl;
            Policy* policy=new Policy;
            policy->appID=appIDSearch;
            char rCount[2];
            rCount[0]=str[i+1];
	    rCount[1] = '\0';
            int ruleCount=atoi(rCount);
            //cout<<"1...\n";
            Rules* rules=new Rules[ruleCount];      // Set the # of rules.
            policy->rule=rules;

            for(int j=0;j<ruleCount;j++)        // looping for each condition
            {
                dataIndex=0;
		memset(metadata,0,20);
                in.getline(str, 255);
                char strCondCount[5] = {0};
                for(i=0;i<strlen(str);i++)
                {
                    if(str[i]!=','){
                        strCondCount[dataIndex]=str[i];
                        dataIndex++;
                    }
                    else{
                        strCondCount[dataIndex]='\0';
                        break;
                    }
                }
                //cout<<"2....\n";
                int condCount = atoi(strCondCount);
                char tempStore[20];
                char data1[10];      // Do not delete this pointer
                int interIndex=0;
                i++;

                ///////////////////

                while(i<strlen(str))
                {
                    tempStore[interIndex]=str[i];
                    i++;
                    interIndex++;
                }
                tempStore[interIndex]='\0';
                int init1=0;
                int j=0;
                    for(;init1<=strlen(tempStore);init1++)
                    {
                        if(tempStore[init1]!=' ' && tempStore[init1]!='\0')
                        {
                            metadata[j]=tempStore[init1];
                            j++;
                        }
                        else
                        {
                          //  j++;
                            metadata[j]='\0';
                            break;
                        }
                    }
                    init1=init1+1;
                    j=0;
                    for(;init1<=strlen(tempStore);init1++)
                    {
                        if(tempStore[init1]!=' ' && tempStore[init1]!='\0')
                        {
                            data1[j]=tempStore[init1];
                            j++;
                        }
                        else
                        {
                         //   j++;
                            data1[j]='\0';
                            break;
                        }
                    }
                    //cout<<"Got - "<<data1<<endl;


                Action* act=new Action; // Assigning actions to rules and itnerfaces to actions.
                ConditionList* cl=new ConditionList[condCount];
                rules[j].action=act;
                //cout<<"Got 1.1- "<<data1<<endl;

                rules[j].condList=cl;

                //cout<<"Got 2 - "<<data1<<endl;
                //cout<<"Got 2 - "<<metadata<<endl;

                if(!strcmp(metadata,"inter"))
                {
                    cout<<"In the interface "<<data1<<endl;
                    Interface* obj = new Interface;
                    act->interface=data1;
                    if(!(obj->interfaceEval(data1)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }
                    delete obj;
                }

                else if(!strcmp(metadata,"loc"))
                {
                    //cout<<"In the location\n";
                    Location* obj = new Location;
                    if(!(obj->resolveLocation(data1)))
                    {
                        //cout<<"Loc does not match "<<data1<<endl;
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;

                    }
                    delete obj;
                }

                else if(!strcmp(metadata,"band"))
                {
                    //act->interface=interfaces;    // we assign the act->interface later on.
                    Bandwidth* obj = new Bandwidth;
                    int band = atoi(data1);
                    /*if(!(obj->resolveBandwidth(band)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }*/
                    delete obj;
                }

                else if(!strcmp(metadata,"cost"))
                {
                    //act->interface=interfaces;    // we assign the act->interface later on.
                    Cost* obj = new Cost;
                    int cost = atoi(data1);
                    /*if(!(obj->resolveCost(cost)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }*/
                    delete obj;
                }

                else if(!strcmp(metadata,"limit"))
                {
                    //act->interface=interfaces;    // we assign the act->interface later on.
                    DownloadLimit* obj = new DownloadLimit;
                    int limit = atoi(data1);
                    /*if(!(obj->resolvedwnLimit(limit)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }*/
                    delete obj;
                }

                cout<<"Trying to check a condition\n";
                // Now loop for condCount
                for(int i=0;i<condCount;i++)
                {
                     in.getline(str, 255);
                    // cout<<"Here..... 2\n";

                     // Working on the first part
                     dataIndex=0;
                     int condOffest=0;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     char data2[20];
                     int init2=0;
                     j=0;
                     condOffest=parseCondition(tempStore,metadata,data2,str,condOffest,init2, dataIndex, j);

                     int status = evaluate(act, cl, metadata, data2);

                    if(!status)
                        continue;


                    // Work on the second part
                     dataIndex=0;
                     condOffest++;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     init2=0;
                     j=0;
                     char* data3 = new char[20];
                    condOffest=parseCondition(tempStore,metadata,data3,str,condOffest,init2, dataIndex, j);
                     status = evaluate(act, cl, metadata, data3);
                     if(!status)
                        continue;


                    // Work on the third part
                     dataIndex=0;
                     condOffest++;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     char* data4 = new char[20];
                     init2=0;
                     j=0;
                    condOffest=parseCondition(tempStore,metadata,data4,str,condOffest,init2, dataIndex, j);
                     status = evaluate(act, cl, metadata, data4);
                     if(!status)
                        continue;


                    // Work on the part4
                     dataIndex=0;
                     condOffest++;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     char* data5 = new char[20];
                     init2=0;
                     j=0;
                     condOffest=parseCondition(tempStore,metadata,data4,str,condOffest,init2, dataIndex, j);
                     status = evaluate(act, cl, metadata, data5);
                     if(!status)
                        continue;
                     //cout<<"???? \n";
                     //delete[] metadata;
                     //delete[] tempStore;
                        
			sine_setHipIf(sockfd, act->interface);
                 //cout<<"!!!!!\n";
                     return act->interface;

                }   // Condition loop ends
            }
            return NULL;
        }   // else ends (I am checking the right policy)
    }   // while ends
}   // function returns


int parseCondition(char* tempStore,char* metadata,char* data2, char* str,int condOffest,int init2,int dataIndex, int j)
{
                     for(;condOffest<strlen(str);condOffest++)
                     {
                        if(str[condOffest]!=','){
                            tempStore[dataIndex]=str[condOffest];
                            dataIndex++;
                        }
                        else{
                            tempStore[dataIndex]='\0';
                            break;
                        }
                     }


                    for(;init2<=strlen(tempStore);init2++)
                    {
                        if(tempStore[init2]!=' ' && tempStore[init2]!='\0')
                        {
                            metadata[j]=tempStore[init2];
                            j++;
                        }
                        else
                        {
                            //j++;
                            metadata[j]='\0';
                            break;
                        }
                    }
                    init2=init2+1;
                    j=0;
                    for(;init2<=strlen(tempStore);init2++)
                    {
                        if(tempStore[init2]!=' ' && tempStore[init2]!='\0')
                        {
                            data2[j]=tempStore[init2];
                            j++;
                        }
                        else
                        {
                           // j++;
                            data2[j]='\0';
			    //cout<<"j = "<<j<<endl;	
                            break;
                        }
                    }
		return condOffest;
}



int evaluate (Action* act, ConditionList* cl, char* metadata, char* data2)
{
		//cout<<"Metadata - "<<metadata<<endl;
                if(!strcmp(metadata,"inter"))
                {
                    act->interface=data2;
                    cout<<"intermediate - "<<act->interface<<" "<<data2;

                    Interface* obj = new Interface;
                    if(!(obj->interfaceEval(data2)))
                        return 0;

                }

                else if(!strcmp(metadata,"loc"))
                {
                       cl->location=new Location;                   // Do not delete strLocation -> memory leak.
                      if(!((cl->location)->resolveLocation(data2)))
                        return 0;

                        delete cl->location;
                }

                else if(!strcmp(metadata,"band"))
                {
                     int bandwidth = atoi(data2);
                     cl->bandwidth=new Bandwidth;
                     if(!((cl->bandwidth)->resolveBandwidth(act->interface, bandwidth)))
                        return 0;
                 
                     delete cl->bandwidth;
                }

                else if(!strcmp(metadata,"cost"))
                {
                     char dataCost[5];
		     char strOffset[5];
		     int offset=0;		
		     int init1=0;

		     int j=0;	
		     for(;init1<=strlen(data2);init1++)
		     {
			if(data2[init1]!='-' && data2[init1]!='\0')
			{
				dataCost[j]=data2[init1];
				j++;
			}
			else
			{
				dataCost[j]='\0';
				break;
			}	
		     }
		     init1=init1+1;
		     j=0;
		     for(;init1<=strlen(data2);init1++)
                     {
                        if(data2[init1]!='-' && data2[init1]!='\0')
                        {
                                strOffset[j]=data2[init1];
                                j++;
                        }
                        else
                        {
                                strOffset[j]='\0';
                                break;
                        }
                     }		

		     int cost = atoi(dataCost);
                     cl->cost=new Cost;
		     offset = atoi(strOffset);
                     if(!((cl->cost)->resolveCost(act->interface, cost, offset)))
                        return 0;
                 
                     delete cl->cost;
                }

                else if(!strcmp(metadata,"limit"))
                {
                    int download = atoi(data2);
                    cl->dwnLimit=new DownloadLimit;
           /*          if(!((cl->dwnLimit)->resolvedwnLimit(download)))
                        return 0;
            */
                    delete cl->dwnLimit;
                }
                //cout<<"Should get - "<<data2<<endl;
                return 1;
}
